package com.yoyosys.db;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.yoyosys.db.partition.vo.Message;
import com.yoyosys.db.partition.vo.SqlReq;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class DbService {
    @Autowired
    private JdbcTemplate defaultJdbcTemplate;

    /**
     * 查询
     * @param sqlReq
     * @return
     */
    public Message query(SqlReq sqlReq) {
        Message message = new Message();
        try {
            JdbcTemplate template = defaultJdbcTemplate;
            if (StrUtil.isNotBlank(sqlReq.getJdbcUrl())) {
                template = getTemplate(sqlReq);
            }
            Assert.notBlank(sqlReq.getSql(), "sql语句不能为空");

            long begin = System.currentTimeMillis();
            log.info("sql: " + sqlReq.getSql() +" begin ...");
            //分页查询
            if(StrUtil.isNotBlank(sqlReq.getCountSql())){
                // 查询总记录数
                int total = template.queryForObject(sqlReq.getCountSql(), Integer.class);
                int pageSize = sqlReq.getPageSize()==null ?  1000 : sqlReq.getPageSize().intValue();
                int pageCount = (int) Math.ceil((double) total / pageSize);
                for (int i=1; i<=pageCount; i++) {
                    int pageStart = (i - 1) * pageSize;;
                    String sql = sqlReq.getSql()
                            .replace("${pageStart}", String.valueOf(pageStart))
                            .replace("${pageSize}", String.valueOf(sqlReq.getPageSize()));
                    long pageBegin = System.currentTimeMillis();
                    List<Map<String, Object>> result = template.queryForList(sql);
                    long pageEnd = System.currentTimeMillis();
                    log.info("page sql["+i+"]: " + sql +", cost(ms):" + (pageEnd - pageBegin));
                    log.debug("page sql["+i+"] result: " + JSON.toJSONString(result));
                }
                long end = System.currentTimeMillis();
                long cost = end - begin;
                message.setCostTime(cost);
                log.info("sql: " + sqlReq.getSql() +", totalCost(ms):" + cost);
            }else {
                List<Map<String, Object>> result = template.queryForList(sqlReq.getSql());
                long end = System.currentTimeMillis();
                long cost = end - begin;
                log.info("sql: " + sqlReq.getSql() +", totalCost(ms):" + cost);
                log.debug("sql: " + sqlReq.getSql() + ", result: " + JSON.toJSONString(result));

                message.setCostTime(cost);
                if(sqlReq.getNeedRet()){
                    message.setData(result);
                }
            }
            message.setCode("200");
            message.setMsg("执行成功");
        } catch (Exception e){
            log.error("query error, SqlReq: " + sqlReq, e);
            message.setMsg("执行失败");
            message.setEndTime(DateUtil.format(new Date(), DatePattern.NORM_DATETIME_FORMAT));
        }

        return message;
    }


    /**
     * 更新
     * @param sqlReq
     * @return
     */
    public Message execute(SqlReq sqlReq) {
        Message message = new Message();
        try {
            JdbcTemplate template = defaultJdbcTemplate;
            if (StrUtil.isNotBlank(sqlReq.getJdbcUrl())) {
                template = getTemplate(sqlReq);
            }
            Assert.notBlank(sqlReq.getSql(), "sql语句不能为空");

            log.info("sql: " + sqlReq.getSql() +" begin ...");
            long begin = System.currentTimeMillis();
            template.execute(sqlReq.getSql());
            long end = System.currentTimeMillis();
            long cost = end - begin;
            log.info("sql: " + sqlReq.getSql() +", totalCost(ms):" + cost);
            message.setCostTime(cost);
            message.setCode("200");
            message.setMsg("执行成功");
        } catch (Exception e){
            log.error("execute error, SqlReq: " + sqlReq, e);
            message.setMsg("执行失败");
            message.setEndTime(DateUtil.format(new Date(), DatePattern.NORM_DATETIME_FORMAT));
        }

        return message;
    }







    private JdbcTemplate getTemplate(SqlReq sqlReq){
        return new JdbcTemplate(getDataSource(sqlReq));
    }

    private DataSource getDataSource(SqlReq sqlReq) {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(sqlReq.getJdbcUrl());
        config.setUsername(sqlReq.getUsername());
        config.setPassword(sqlReq.getPassword());
        config.setDriverClassName(sqlReq.getDriverClass());
        config.setMaximumPoolSize(10);
        config.setMinimumIdle(2);
        config.setConnectionTimeout(30000);

        return new HikariDataSource(config);

    }

}
